#include "Game.h"

/**
 * 构造方法。
 * @param bitmap    后台缓冲位图
 * @param gameBoard 游戏区域
 */
Game::Game(QPixmap* bitmap, QWidget* gameBoard) :
    mApple(nullptr),
    mBitmap(bitmap),
    mDifficulty(1),
    mEnableMusic(false),
    mGameBoard(gameBoard),
    mMusicPlayer(Const::MUSIC_FILE_NAME),
    mScore(0),
    mSnake(nullptr),
    mStatus(END) {
    // 重绘游戏区域
    this->drawGameBoard();

    // 置随机数种子
    srand(static_cast<uint>(time(nullptr)));

    // 连接信号与槽
    QObject::connect(&mTimer, SIGNAL(timeout()), SLOT(onTimer()));

    // 设置音乐播放模式为无限循环
    mMusicPlayer.setLoops(QSound::Infinite);
}

/**
 * 在随机位置创建果子。
 */
void Game::createApple() {
    QPoint point;
    bool used = false;

    // 创建果子
    do {
        // 取 x、y 的随机值
        point.setX(rand() % (Const::GAME_BOARD_GRID_COUNT_H - 2) + 1);
        point.setY(rand() % (Const::GAME_BOARD_GRID_COUNT_V - 2) + 1);
        used = this->pointIsUsed(&point);
    } while (used);
    mApple = new SnakeBody(mBitmap, &point, SnakeBody::APPLE);
}

/**
 * 画游戏区域。
 */
void Game::drawGameBoard() {
    mDrawer.begin(mBitmap);
    mDrawer.fillRect(0, 0, Const::GAME_BOARD_WIDTH, Const::GAME_BOARD_HEIGHT, Const::GAME_BOARD_COLOR);
    mDrawer.end();
}

/**
 * 游戏结束。
 * @param isWon 胜利则为 true，否则为 false
 */
void Game::gameOver(bool isWon) {
    // 将状态设置为已结束
    mStatus = END;

    // 停止定时器
    mTimer.stop();

    // 停止播放音乐
    if (mEnableMusic) {
        mMusicPlayer.stop();
    }

    // 发送通知
    emit UM_GAME_OVER(isWon);
}

/**
 * 获取游戏状态。
 * @return 游戏状态
 */
Game::Status Game::getStatus() {
    return mStatus;
}

/**
 * 判断是否胜利。
 * @return 胜利则返回 true，否则返回 false
 */
bool Game::isWon() {
    return mScore >= Const::WIN_NUMBER;
}

/**
 * 按键事件的响应方法。
 * @param key   按键
 */
void Game::onKeyPressed(int key) {
    if (mStatus != PLAYING) {
        return;
    }
    if (key >= Qt::Key_Left && key <= Qt::Key_Down) {
        mSnake->turn(key);
    }
}

/**
 * 定时器事件的响应方法。
 */
void Game::onTimer() {
    // 移动蛇
    bool isDead = mSnake->move();
    if (isDead) {
        this->gameOver(false);
        return;
    }

    // 检查是否碰到果子
    SnakeBody* head = mSnake->getHead();
    if (*head->getPosition() == *mApple->getPosition()) {
        // 碰到果子，将果子加入蛇链表
        mSnake->eat(mApple);
        this->createApple();
        mScore++;
        emit UM_SCORE(mScore);

        // 判断是否胜利
        if (this->isWon()) {
            this->gameOver(true);
            return;
        }

        // 判断是否达到增加难度的条件
        if (mScore % Const::DIFF_BASE == 0 && mDifficulty != Const::DIFF_MAX) {
            mDifficulty++;
            emit UM_DIFFICULTY_UP(mDifficulty);
            mTimer.stop();
            int elapse = Const::TIMER_INIT - Const::TIMER_GROW * (mDifficulty - 1);
            mTimer.start(elapse);
        }
    }

    // 通知游戏区域重绘
    mGameBoard->update();
}

/**
 * 游戏暂停。
 */
void Game::pause() {
    if (mStatus == PLAYING) {
        // 停止定时器
        mTimer.stop();

        // 停止播放音乐
        if (mEnableMusic) {
            mMusicPlayer.stop();
        }

        // 将状态设置为已暂停
        mStatus = PAUSED;
    } else if (mStatus == PAUSED) {
        // 开启定时器
        mTimer.start(Const::TIMER_INIT - Const::TIMER_GROW * (mDifficulty - 1));

        // 播放音乐
        if (mEnableMusic) {
            mMusicPlayer.play();
        }

        // 将状态设置为游戏中
        mStatus = PLAYING;
    }
}

/**
 * 播放音乐。
 * @return 正在播放音乐则为 true，否则为 false
 */
bool Game::playMusic() {
    mEnableMusic = !mEnableMusic;

    if (mEnableMusic) {
        if (mStatus == PLAYING) {
            mMusicPlayer.play();
        }
    } else {
        mMusicPlayer.stop();
    }

    return mEnableMusic;
}

/**
 * 判断某个点是否被占用。
 * @param point 点
 * @return 被占用了则返回 true，否则返回 false
 */
bool Game::pointIsUsed(QPoint* point) {
    // 检查点是否在蛇上
    if (mSnake->pointIsOnMe(point)) {
        return true;
    }

    // 检查点是否在果子上
    if (mApple != nullptr) {
        return point == mApple->getPosition();
    }

    return false;
}

/**
 * 游戏开始。
 */
void Game::start() {
    // 重绘游戏区域
    this->drawGameBoard();

    // 创建蛇
    if (mSnake != nullptr) {
        delete mSnake;
    }
    mSnake = new Snake(mBitmap);

    // 创建果子
    if (mApple != nullptr) {
        delete mApple;
    }
    this->createApple();

    // 通知游戏区域重绘
    mGameBoard->update();

    // 重置难度
    mDifficulty = 1;

    // 重置分数
    mScore = 0;

    // 开启定时器
    mTimer.stop();
    mTimer.start(Const::TIMER_INIT);

    // 播放音乐
    if (mEnableMusic) {
        mMusicPlayer.play();
    }

    // 将状态设置为游戏中
    mStatus = PLAYING;
}
